home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / Source.bin / RadioButtonGroupPanel.java < prev    next >
Text File  |  1998-08-21  |  16KB  |  488 lines

  1. package symantec.itools.awt;
  2.  
  3. import java.awt.Panel;
  4. import java.awt.Checkbox;
  5. import java.awt.CheckboxGroup;
  6. import java.awt.Component;
  7. import java.awt.AWTEventMulticaster;
  8. import java.awt.event.ItemEvent;
  9. import java.awt.event.ItemListener;
  10. import java.util.Vector;
  11. import java.beans.PropertyVetoException;
  12. import java.beans.PropertyChangeListener;
  13. import java.beans.VetoableChangeListener;
  14. import java.beans.PropertyChangeEvent;
  15. import java.util.ResourceBundle;
  16.  
  17. //    01/27/97    RKM    Changed moveIntoGroup to preserve checkbox's state
  18. //    01/29/97    TWB    Integrated changes from Windows and RKM's changes
  19. //     01/29/97    TWB    Integrated changes from Macintosh
  20. //    06/01/97    RKM    Updated to support Java 1.1
  21. //                    Updated mechanism to keep track of contents of panel
  22. //    09/10/97    LAB    Made it extend BorderPanel to give it BorderPanel's properties (Addresses Mac
  23. //                    Bug #3086).  Made it fire an ItemEvent when the "station" changes (Addresses
  24. //                    Mac Bug #3093).
  25. //    10/05/97    LAB    Added mechanism for values passed to setSelectedRadioButtonIndex to be
  26. //                    validated on each call to addImpl to avoid code-gen order specific
  27. //                    dependencies.
  28.  
  29. /**
  30.  * Creates an rectangular panel area that automatically groups
  31.  * the RadioButtons that it contains.
  32.  * <p>
  33.  * All the RadioButtons within the RadioButtonGroupPanel act together. Only
  34.  * one of the RadioButtons can be "on" at a time.
  35.  * <p>
  36.  * @version 1.1, August 22, 1997
  37.  * @author Symantec
  38.  */
  39. public class RadioButtonGroupPanel extends BorderPanel implements java.awt.ItemSelectable
  40. {
  41.     /**
  42.      * Constructs a RadioButtonGroupPanel.
  43.      */
  44.     public RadioButtonGroupPanel()
  45.     {
  46.         group = new CheckboxGroup();
  47.         try
  48.         {
  49.             setPaddingTop(0);
  50.             setPaddingBottom(0);
  51.             setPaddingLeft(0);
  52.             setPaddingRight(0);
  53.         }
  54.         catch (PropertyVetoException exc) {}
  55.  
  56.         rbList = new Vector();
  57.         item = new IL();
  58.         tempSelectionIndex = -1;
  59.     }
  60.  
  61.     /**
  62.      * Returns the selected items or null if no items are selected.
  63.      */
  64.     public Object[] getSelectedObjects()
  65.     {
  66.         Object object[] = {getSelectedRadioButton()};
  67.         return object;
  68.     }
  69.  
  70.     /**
  71.      * Sets the current choice to the specified RadioButton.
  72.      * @param rb the current RadioButton (CheckBox) choice
  73.      * @exception PropertyVetoException if the recipient wishes the property
  74.      *              change to be rolled back.
  75.      */
  76.     public synchronized void setSelectedRadioButton(Checkbox rb) throws PropertyVetoException
  77.     {
  78.         Checkbox oldValue = getSelectedRadioButton();
  79.         if(! symantec.itools.util.GeneralUtils.objectsEqual(rb, oldValue))
  80.         {
  81.             vetos.fireVetoableChange("selectedRadioButton", oldValue, rb);
  82.  
  83.             group.setSelectedCheckbox(rb);
  84.             //Fire an event to our listeners, since the previous line doensn't seem to result in an event being fired.
  85.             sourceItemEvent(rb);
  86.  
  87.             changes.firePropertyChange("selectedRadioButton", oldValue, getSelectedRadioButton());
  88.         }
  89.     }
  90.  
  91.     /**
  92.      * Gets the current choice.
  93.      */
  94.     public Checkbox getSelectedRadioButton()
  95.     {
  96.         return group.getSelectedCheckbox();
  97.     }
  98.  
  99.     /**
  100.      * Sets the current choice to the specified RadioButton.
  101.      * @param index the index of the RadioButton to be the selected.
  102.      * @see #getSelectedRadioButtonIndex
  103.      * @exception PropertyVetoException if the recipient wishes the property
  104.      *              change to be rolled back.
  105.      */
  106.     public synchronized void setSelectedRadioButtonIndex(int index) throws PropertyVetoException
  107.     {
  108.         tempSelectionIndex = index;
  109.         if(isAdded)
  110.         {
  111.             Integer oldValue = new Integer(getSelectedRadioButtonIndex());
  112.             if(oldValue.intValue() != index)
  113.             {
  114.                 Integer newValue = new Integer(index);
  115.                 vetos.fireVetoableChange("selectedRadioButtonIndex", oldValue, newValue);
  116.  
  117.                 setSelectedRadioButton((Checkbox)rbList.elementAt(index));
  118.  
  119.                 changes.firePropertyChange("selectedRadioButtonIndex", oldValue, newValue);
  120.             }
  121.         }
  122.     }
  123.  
  124.     /**
  125.      * Gets the index of the current choice.
  126.      * @return the index of the selected RadioButton.  -1 if no selection.
  127.      * @see #setSelectedRadioButtonIndex
  128.      */
  129.     public int getSelectedRadioButtonIndex()
  130.     {
  131.         Checkbox cb = getSelectedRadioButton();
  132.         if(cb != null && rbList.contains(cb))
  133.         {
  134.             for(int i = 0; i < rbList.size(); i++)
  135.             {
  136.                 if((Checkbox)rbList.elementAt(i) == cb)
  137.                     return i;
  138.             }
  139.         }
  140.         return -1;
  141.     }
  142.  
  143.     /**
  144.      * Returns the String representation of this RadioButtonGroup's values.
  145.      * Convert to String.
  146.      */
  147.     public String toString()
  148.     {
  149.         return getClass().getName() + "[selectedRadioButton=" + getSelectedRadioButton() + "]";
  150.     }
  151.  
  152.     /**
  153.      * Removes the component at the specified index from this container.
  154.      * @param index the index of the component to be removed
  155.      * @see java.awt.Container#add
  156.      */
  157.     public void remove(int index)
  158.     {
  159.         Component comp = getComponent(index);
  160.  
  161.         if(comp instanceof Checkbox)
  162.         {
  163.             ((Checkbox)comp).removeItemListener(item);
  164.             //Remove it from out internal list.
  165.             rbList.removeElement(comp);
  166.         }
  167.  
  168.         super.remove(index);
  169.     }
  170.  
  171.     /**
  172.      * Removes all the components from this container.
  173.      * @see java.awt.Container#add
  174.      * @see #remove
  175.      */
  176.     public void removeAll()
  177.     {
  178.         Component[] comp = getComponents();
  179.  
  180.         for (int i = 0; i < comp.length; ++i)
  181.         {
  182.             if(comp[i] instanceof Checkbox)
  183.                 ((Checkbox)comp[i]).removeItemListener(item);
  184.         }
  185.  
  186.         //Reset our internal list.
  187.         rbList = new Vector();
  188.  
  189.         super.removeAll();
  190.     }
  191.  
  192.     /**
  193.      * Tells this component that it has been added to a container.
  194.      * This is a standard Java AWT method which gets called by the AWT when
  195.      * this component is added to a container. Typically, it is used to
  196.      * create this component's peer.
  197.      *
  198.      * It has been overridden here to hook-up event listeners.
  199.      *
  200.      * @see #removeNotify
  201.      */
  202.     public synchronized void addNotify()
  203.     {
  204.         super.addNotify();
  205.         errors = ResourceBundle.getBundle("symantec.itools.resources.ErrorsBundle");
  206.  
  207.         //Hook up listeners
  208.         if (indexVeto == null)
  209.         {
  210.             indexVeto = new IV();
  211.             addSelectedRadioButtonIndexListener(indexVeto);
  212.         }
  213.         isAdded = true;
  214.     }
  215.  
  216.     /**
  217.      * Tells this component that it is being removed from a container.
  218.      * This is a standard Java AWT method which gets called by the AWT when
  219.      * this component is removed from a container. Typically, it is used to
  220.      * destroy the peers of this component and all its subcomponents.
  221.      *
  222.      * It has been overridden here to unhook event listeners.
  223.      *
  224.      * @see #addNotify
  225.      */
  226.     public synchronized void removeNotify()
  227.     {
  228.         //Unhook listeners
  229.         if (indexVeto != null)
  230.         {
  231.             removeSelectedRadioButtonIndexListener(indexVeto);
  232.             indexVeto = null;
  233.         }
  234.  
  235.         super.removeNotify();
  236.     }
  237.  
  238.     /**
  239.      * Adds a listener for all event changes.
  240.      * @param listener the listener to add.
  241.      * @see #removePropertyChangeListener
  242.      */
  243.     public synchronized void addPropertyChangeListener(PropertyChangeListener listener)
  244.     {
  245.         super.addPropertyChangeListener(listener);
  246.         changes.addPropertyChangeListener(listener);
  247.     }
  248.  
  249.     /**
  250.      * Removes a listener for all event changes.
  251.      * @param listener the listener to remove.
  252.      * @see #addPropertyChangeListener
  253.      */
  254.     public synchronized void removePropertyChangeListener(PropertyChangeListener listener)
  255.     {
  256.         super.removePropertyChangeListener(listener);
  257.         changes.removePropertyChangeListener(listener);
  258.     }
  259.  
  260.     /**
  261.      * Adds a vetoable listener for all event changes.
  262.      * @param listener the listener to add.
  263.      * @see #removeVetoableChangeListener
  264.      */
  265.     public synchronized void addVetoableChangeListener(VetoableChangeListener listener)
  266.     {
  267.         super.addVetoableChangeListener(listener);
  268.         vetos.addVetoableChangeListener(listener);
  269.     }
  270.  
  271.     /**
  272.      * Removes a vetoable listener for all event changes.
  273.      * @param listener the listener to remove.
  274.      * @see #addVetoableChangeListener
  275.      */
  276.     public synchronized void removeVetoableChangeListener(VetoableChangeListener listener)
  277.     {
  278.         super.removeVetoableChangeListener(listener);
  279.         vetos.removeVetoableChangeListener(listener);
  280.     }
  281.  
  282.     /**
  283.      * Adds a listener for the SelectedRadioButtonIndex property changes.
  284.      * @param listener the listener to add.
  285.      * @see #removeSelectedRadioButtonIndexListener(java.beans.PropertyChangeListener)
  286.      */
  287.     public synchronized void addSelectedRadioButtonIndexListener(PropertyChangeListener listener)
  288.     {
  289.         changes.addPropertyChangeListener("selectedRadioButtonIndex", listener);
  290.     }
  291.  
  292.     /**
  293.      * Removes a listener for the SelectedRadioButtonIndex property changes.
  294.      * @param listener the listener to remove.
  295.      * @see #addSelectedRadioButtonIndexListener(java.beans.PropertyChangeListener)
  296.      */
  297.     public synchronized void removeSelectedRadioButtonIndexListener(PropertyChangeListener listener)
  298.     {
  299.         changes.removePropertyChangeListener("selectedRadioButtonIndex", listener);
  300.     }
  301.  
  302.     /**
  303.      * Adds a vetoable listener for the SelectedRadioButtonIndex property changes.
  304.      * @param listener the listener to add.
  305.      * @see #removeSelectedRadioButtonIndexListener(java.beans.VetoableChangeListener)
  306.      */
  307.     public synchronized void addSelectedRadioButtonIndexListener(VetoableChangeListener listener)
  308.     {
  309.         vetos.addVetoableChangeListener("selectedRadioButtonIndex", listener);
  310.     }
  311.  
  312.     /**
  313.      * Removes a vetoable listener for the SelectedRadioButtonIndex property changes.
  314.      * @param listener the listener to remove.
  315.      * @see #addSelectedRadioButtonIndexListener(java.beans.VetoableChangeListener)
  316.      */
  317.     public synchronized void removeSelectedRadioButtonIndexListener(VetoableChangeListener listener)
  318.     {
  319.         vetos.removeVetoableChangeListener("selectedRadioButtonIndex", listener);
  320.     }
  321.  
  322.     /**
  323.      * Adds the specified item listener to receive item events
  324.      * from this component.
  325.      * @param l the item listener
  326.      * @see #removeItemListener
  327.      */
  328.     public synchronized void addItemListener(ItemListener l)
  329.     {
  330.         itemListener = AWTEventMulticaster.add(itemListener, l);
  331.     }
  332.  
  333.     /**
  334.      * Removes the specified Item listener so it no longer receives
  335.      * Item events from this component.
  336.      * @param l the action listener
  337.      * @see #addItemListener
  338.      */
  339.     public synchronized void removeItemListener(ItemListener l)
  340.     {
  341.         itemListener = AWTEventMulticaster.remove(itemListener, l);
  342.     }
  343.  
  344.     /**
  345.      * This is the Item Event handling innerclass.
  346.      */
  347.     class IL implements java.awt.event.ItemListener
  348.     {
  349.         /**
  350.          * Handles Item State Changed events
  351.          * @param e the ItemEvent
  352.          */
  353.         public void itemStateChanged(ItemEvent e)
  354.         {
  355.             sourceItemEvent((Checkbox) e.getSource());
  356.         }
  357.     }
  358.  
  359.     /**
  360.      * This is the PropertyChangeEvent handling inner class for the constrained SelectedRadioButtonIndex property.
  361.      * Handles vetoing SelectedRadioButtonIndex indexes that are not valid.
  362.      */
  363.     class IV implements java.beans.VetoableChangeListener, java.io.Serializable
  364.     {
  365.         /**
  366.          * This method gets called when an attempt to change the constrained Frame property is made.
  367.          * Ensures the given Frame string is valid for this button.
  368.          *
  369.          * @param     e a <code>PropertyChangeEvent</code> object describing the
  370.          *             event source and the property that has changed.
  371.          * @exception PropertyVetoException if the recipient wishes the property
  372.          *              change to be rolled back.
  373.          */
  374.         public void vetoableChange(PropertyChangeEvent e) throws PropertyVetoException
  375.         {
  376.             int i = ((Integer)e.getNewValue()).intValue();
  377.             if (!isValidSelectedRadioButtonIndex(i))
  378.             {
  379.                 throw new PropertyVetoException(errors.getString("InvalidSelectedRadioButtonIndex") + i, e);
  380.             }
  381.         }
  382.     }
  383.  
  384.     /**
  385.      * Is the given index value valid.
  386.      * @param index the given index to test
  387.      * @return true if the given index is acceptable, false if not.
  388.      * To be valid it has to be within the limits of the rbList:
  389.      */
  390.     protected boolean isValidSelectedRadioButtonIndex(int index)
  391.     {
  392.         if(rbList != null && index < rbList.size() && index >= 0)
  393.             return true;
  394.         else
  395.             return false;
  396.     }
  397.  
  398.     /**
  399.      * Fires an item event to the listeners.
  400.      * @param item the radio button that changed state
  401.      */
  402.     protected void sourceItemEvent(Checkbox item)
  403.     {
  404.         if(item != lastItem)
  405.         {
  406.             if (itemListener != null)
  407.                 itemListener.itemStateChanged(new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED, item, (item.getState() ? ItemEvent.SELECTED : ItemEvent.DESELECTED)));
  408.             lastItem = item;
  409.         }
  410.     }
  411.  
  412.     protected void addImpl(Component component, Object constraints, int index)
  413.     {
  414.         moveIntoGroup(component);
  415.  
  416.         super.addImpl(component,constraints,index);
  417.         if(isValidSelectedRadioButtonIndex(tempSelectionIndex))
  418.             try { setSelectedRadioButtonIndex(tempSelectionIndex); } catch (PropertyVetoException exc) { /*Silently verify.*/ }
  419.  
  420.     }
  421.  
  422.     /**
  423.      * Internal helper method.
  424.      * Adds the given Checkbox into this panel's CheckboxGroup without changing
  425.      * its "selected" state.
  426.      * @param component the Checkbox to add to this RadioButtonGroupPanel
  427.      */
  428.     protected void moveIntoGroup(Component component)
  429.     {
  430.         if(!(component instanceof Checkbox))
  431.         {
  432.             return;
  433.         }
  434.  
  435.         //Cast the component to a checkbox
  436.         Checkbox checkBox = ((Checkbox)component);
  437.  
  438.         //Save the state
  439.         boolean savedState = checkBox.getState();
  440.  
  441.         //Set up the checkbox group
  442.         checkBox.setCheckboxGroup(group);
  443.  
  444.         //Restore the state if it was true
  445.         if (savedState)
  446.             checkBox.setState(savedState);
  447.  
  448.         checkBox.addItemListener(item);
  449.  
  450.         //Keep the component in our internal vector.
  451.         rbList.addElement(checkBox);
  452.     }
  453.  
  454.     /**
  455.      * The Checkbox group for the radio buttons.
  456.      */
  457.     protected CheckboxGroup group;
  458.     /**
  459.      * Vector of Checkboxes added to the panel.  Used to set selected RadioButton by index.
  460.      */
  461.     protected Vector    rbList;
  462.     /**
  463.      * Listener(s) that get notified when an ItemEvent is generated.
  464.      */
  465.     protected ItemListener itemListener = null;
  466.     /**
  467.      * Internal use.
  468.      * Remembers the requested selected index so that <code>setSelectedIndex</code>
  469.      * may be called before the appropriate radio button has been added.
  470.      */
  471.     protected int tempSelectionIndex;
  472.     /**
  473.      * is the component added to a container hierarchy?
  474.      */
  475.     protected boolean   isAdded = false;
  476.     /**
  477.      * Error strings.
  478.      */
  479.     transient protected ResourceBundle errors;
  480.  
  481.     private IL            item        = null;
  482.     private IV            indexVeto    = null;
  483.     private Checkbox    lastItem    = null;
  484.     private symantec.itools.beans.VetoableChangeSupport vetos = new symantec.itools.beans.VetoableChangeSupport(this);
  485.     private symantec.itools.beans.PropertyChangeSupport changes = new symantec.itools.beans.PropertyChangeSupport(this);
  486. }
  487.  
  488.